/*
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is ST_EXT-S_UIMAST.
 *
 * The Initial Developer of the Original Code is
 * University of Rome, Tor Vergata
 * Portions created by the Initial Developer are Copyright (C) 2009
 * the Initial Developer. All Rights Reserved.
 */

package it.uniroma2.art.uimast.impl;

import it.uniroma2.art.ontapi.*;
import it.uniroma2.art.semanticturkey.resources.Resources;
import it.uniroma2.art.uimast.xpts.Variant;

import java.util.Iterator;
import org.w3c.dom.Element;

/**
 * A data source representing a property.
 */
public class PropertyDataSource extends DataSource
{

	/**
	 * Constructs a <code>PropertyDataSource</code>
	 * @param v the prototype variant (of the appropriate concrete class)
	 * @param srcClass the source class ({@code null} if it is a wired property)
	 * @param property the property resource
	 * @throws Exception
	 */
    public PropertyDataSource(Variant v, ARTResource srcClass, ARTResource property)
        throws Exception
    {
        super(v);
        
        // Stores the property.
        this.property = property;
        
        // If srcClass is null, then assumes it is a wired property
        if (srcClass == null)
        	return;
        
        // Gets the ontology repository interface.
        ARTRepository repository = Resources.getRepository();
        
    	// Gets the property domains.
        Iterator<ARTResource> it = repository.getPropertyDomains(property, false);
        
        // Iterates over the domains.
        while(it.hasNext())
        {
        	// Gets the current domain
            ARTResource d = it.next();
            
            // Checks that the source class extends the current domain
            if(!AnnotationProjection.subclasses(srcClass, d))
                throw new Exception("The class \"" + srcClass.getURI() + "\" isn't a subset of the domain of the property \"" + property.getURI() + "\"");
        }

        //// Checks that the property has just a range compatible with the variant underlying type
        it = repository.getPropertyRanges(property);
        if(!it.hasNext())
            throw new Exception("The property \"" + property.getURI() + "\" has no range");
        if(!v.isCompatible(it.next()))
            throw new Exception("The property \"" + property.getURI() + "\" has an incompatible range");
        if(it.hasNext())
            throw new Exception("The property \"" + property.getURI() + "\" has multiple ranges");
    }

    @Override
    public Iterator<Variant> apply(ARTResource domainObject, ARTResource annot)
    {
    	// Gets the ontology repository interface.
        ARTRepository repository = Resources.getRepository();
        
        // Gets the property values
        final Iterator<ARTLiteral> it = repository.listSTDatatypePropertyValues(domainObject, property);
        
        // Returns a new iterator
        return new Iterator<Variant>() {

        	// Checks that there is another value
            public boolean hasNext()
            {
        		// If the current value wasn't read, then returns true
        		if(!read)
        			return true;
        		
        		// Otherwise, finds the next value
                while(it.hasNext()) 
                {
                	// Gets the next value (as lexical representation)
                    String t = ((ARTLiteral)it.next()).getLabel();
                   
                    // Assigns the current value to the variant
                    if(v.setValue(t)) {
                    	// If the value is correct, then read=false and returns true
                    	read=false;
                        return true;
                    }
                }
                
                return false;
            }

            // Gets the next property value
            public Variant next()
            {
            	read = true;
                return v.clone();
            }

            // The remove method isn't supported
            public void remove()
            {
                throw new UnsupportedOperationException("Cannot delete elements from a read only sequence");
            }
            
            // Flag denoting if the current value was read
            private boolean read = true; 
        };
    }

    @Override
    public void toDOM(Element e)
    {
        e.setAttribute("property", property.getURI());
    }

    /** The property resource. */
    protected ARTResource property;
}
